<script setup lang="ts">
import { filter } from 'lodash-es'
import {
  ElButton,
  ElSelect,
  ElOption,
  ElInput,
  ElMessageBox,
  ElDialog,
  ElForm,
  ElFormItem,
  FormInstance,
  FormRules,
  ElNotification,
  ElTabs,
  ElTabPane,
  ElTree,
  ElCheckbox
} from 'element-plus'
import { Plus, Lock, Unlock, CirclePlus } from '@element-plus/icons-vue'
import { Table } from '@/components/Table'
import {
  getUsersListApi,
  delUsersListApi,
  unlockUserApi,
  resetPasswordApi,
  getUserHotelPermissionsApi,
  grantUserHotelApi,
  revokeUserHotelApi,
  getUserGrantedHotelsApi,
  grantUserHotelPermissionsApi
} from '@/api/user'
import { useTable } from '@/hooks/web/useTable'
import { reactive, ref, unref, computed, nextTick } from 'vue'
import { useRouter } from 'vue-router'
import { useEmitt } from '@/hooks/web/useEmitt'
import { TableColumn } from '@/types/table'
import { Search, SearchItem } from '@/components/Search'
import { User } from '@/api/user/types'
import { formatDate } from '@/utils'
import { useValidator } from '@/hooks/web/useValidator'
import { useSessionStore } from '@/store/modules/session'
import { Hotel } from '@/api/hotel/types'
import type Node from 'element-plus/es/components/tree/src/model/node'

defineOptions({
  name: 'UserIndex'
})

const { push } = useRouter()
const { required } = useValidator()
const sessionStore = useSessionStore()

const hotels = computed(() => sessionStore.getHotels)
const view_role = computed(() => sessionStore.getViewRole)

const { register, tableObject, methods } = useTable<User>({
  getListApi: getUsersListApi,
  delListApi: delUsersListApi
})

const { getList, setSearchParams } = methods

getList()

useEmitt({
  name: 'getList',
  callback: (type: string) => {
    if (type === 'add') {
      tableObject.currentPage = 1
    }
    getList()
  }
})

const delLoading = ref(false)
const resetPasswordLoading = ref(false)
const resetPasswordFormRef = ref<FormInstance>()
const resetPasswordDialogVisible = ref(false)
const resetPasswordInstance = reactive({
  password: '',
  grant_password: ''
})

const grantFormRef = ref<FormInstance>()
const treeRef = ref<InstanceType<typeof ElTree>>()
const grantDialogVisible = ref(false)
const grantLoading = ref(false)
const grantInstance = reactive({
  hotel_id: ''
})
const grantHotels = reactive<Hotel[]>([])
const permissionTrees = reactive([])
const currentTab = ref('0')

const treeRef2 = ref<InstanceType<typeof ElTree>>()
const grantDialogVisible2 = ref(false)

const getAllKeys = (keys, permissions) => {
  if (Array.isArray(permissions)) {
    for (const item of permissions) {
      keys.push(item.id)
      getAllKeys(keys, item.children)
    }
  }

  return keys
}

const getRootKeys = () => {
  return filter(permissionTrees, { parent_code: 0 })
}

const checkPassword = (_: any, value: any, callback: any) => {
  if (!value) {
    return callback(new Error('请输入新密码'))
  } else if (value.length < 6) {
    return callback(new Error('密码长度应不小于6'))
  }

  callback()
}

const resetPasswordRules = reactive<FormRules>({
  password: [required('请输入重置的新密码'), { validator: checkPassword }],
  grant_password: [required('请输入您的密码')]
})

const tableColumns = reactive<TableColumn[]>([
  {
    field: 'xfull_name',
    label: '姓名',
    width: '160px',
    showOverflowTooltip: true
  },
  {
    field: 'login_name',
    label: '用户名',
    width: '120px',
    showOverflowTooltip: true
  },
  {
    field: 'department',
    label: '部门',
    width: '140px',
    showOverflowTooltip: true
  },
  {
    field: 'position',
    label: '职位',
    width: '140px',
    showOverflowTooltip: true
  },
  {
    field: 'mobile',
    label: '手机',
    width: '140px',
    showOverflowTooltip: true
  },
  {
    field: 'email',
    label: '邮箱',
    width: '120px',
    showOverflowTooltip: true
  },
  {
    field: 'reference',
    label: '备注',
    width: 'auto',
    showOverflowTooltip: true
  },
  {
    field: 'last_login',
    label: '最近登录',
    width: '180px',
    showOverflowTooltip: true,
    formatter: (_: Recordable, __: TableColumn, cellValue: number) => {
      return formatDate(cellValue)
    }
  },
  {
    field: 'action',
    width: '120px',
    label: '操作',
    headerAlign: 'center',
    align: 'center'
  }
])

const AddAction = () => {
  push('/user/user-add')
}

const EditAction = (row: User) => {
  push(`/user/user-edit/id/${row.id}`)
}

const unlockAction = () => {
  if (tableObject.currentRow) {
    ElMessageBox.confirm(`确定解锁用户: ${tableObject.currentRow.login_name} ?`, '操作提醒').then(
      async () => {
        const res = await unlockUserApi({ user_id: tableObject.currentRow?.id })
        if (res) {
          await getList()
        }
      }
    )
  }
}

const resetPasswordAction = () => {
  if (tableObject.currentRow) {
    resetPasswordInstance.password = ''
    resetPasswordInstance.grant_password = ''
    resetPasswordDialogVisible.value = true
  }
}

const onResetPasswordConfirm = async () => {
  const form = unref(resetPasswordFormRef)
  await form?.validate().then(async (valid) => {
    if (valid) {
      const res = await resetPasswordApi({
        user_id: tableObject.currentRow?.id,
        ...resetPasswordInstance
      })
      if (res) {
        ElNotification({
          title: '操作成功',
          message: '密码已重置。',
          type: 'success'
        })
        resetPasswordDialogVisible.value = false
        await getList()
      }
    }
  })
}

const grantAction = async () => {
  if (tableObject.currentRow) {
    const res = await getUserGrantedHotelsApi(tableObject.currentRow.id)
    let granted = []
    if (res) {
      grantHotels.length = 0
      Object.assign(grantHotels, res.data.rows)
      if (grantHotels.length > 0) {
        // 获取当前主体权限
        const res = await getUserHotelPermissions(tableObject.currentRow.id, grantHotels[0].id)
        if (res) {
          granted = res.granted
        }
      }
    }

    grantDialogVisible.value = true
    nextTick(() => {
      treeRef.value!.setCheckedKeys(granted, false)
    })
  }
}

const grantAction2 = async () => {
  if (tableObject.currentRow) {
    let granted = []

    const res = await getUserHotelPermissions(tableObject.currentRow.id, sessionStore.getHotelId)
    if (res) {
      granted = res.granted
    }

    grantDialogVisible2.value = true
    nextTick(() => {
      treeRef2.value!.setCheckedKeys(granted, false)
    })
  }
}

// 获取用户主体权限
const getUserHotelPermissions = async (user_id, hotel_id) => {
  const res = await getUserHotelPermissionsApi(user_id, hotel_id)
  if (res) {
    permissionTrees.length = 0
    Object.assign(permissionTrees, res.data.tree)
    return res.data
  }
  return null
}

const grantHotelAction = async () => {
  const res = await grantUserHotelApi({
    hotel_id: grantInstance.hotel_id,
    user_id: tableObject.currentRow?.id
  })

  if (res) {
    await grantAction()
  }
}

const revokeHotelAction = async () => {
  if (grantHotels[currentTab.value]) {
    const hotel = grantHotels[currentTab.value]
    ElMessageBox.confirm(`确定将当前用户移出${hotel.name}，并撤销所有权限。此操作不可逆。`, {
      title: '提示',
      type: 'warning'
    })
      .then(async () => {
        const res = await revokeUserHotelApi({
          hotel_id: hotel.id,
          user_id: tableObject.currentRow?.id
        })

        if (res) {
          await grantAction()
        }
      })
      .catch(() => {})
  }
}

const expandAction = (e: boolean) => {
  const keys = getRootKeys()
  for (const key of keys) {
    const node = treeRef.value!.getNode(key) as Node
    node.expanded = e
  }
}

const selectAllAction = (e: boolean) => {
  if (!e) {
    treeRef.value!.setCheckedKeys([], false)
  } else {
    treeRef.value!.setCheckedKeys(getAllKeys([], permissionTrees), false)
  }
}

const onGrantPermissionsConfirm = async () => {
  grantLoading.value = true
  const keys = treeRef.value!.getCheckedKeys()
  const hotel = grantHotels[currentTab.value]
  grantUserHotelPermissionsApi(tableObject.currentRow?.id, hotel.id, keys)
    .then((res) => {
      if (res) {
        ElNotification({
          title: '操作成功',
          type: 'success'
        })
      }
    })
    .finally(() => {
      grantLoading.value = false
    })
}

const revokeHotelAction2 = async (row) => {
  ElMessageBox.confirm(`确定将当前用户移出当前酒店，并撤销所有权限。此操作不可逆。`, {
    title: '提示',
    type: 'warning'
  })
    .then(async () => {
      const res = await revokeUserHotelApi({
        hotel_id: sessionStore.getHotelId,
        user_id: row.id
      })

      if (res) {
        grantDialogVisible2.value = false
        await getList()
      }
    })
    .catch(() => {})
}

const expandAction2 = (e: boolean) => {
  const keys = getRootKeys()
  for (const key of keys) {
    const node = treeRef2.value!.getNode(key) as Node
    node.expanded = e
  }
}

const selectAllAction2 = (e: boolean) => {
  if (!e) {
    treeRef2.value!.setCheckedKeys([], false)
  } else {
    treeRef2.value!.setCheckedKeys(getAllKeys([], permissionTrees), false)
  }
}

const onGrantPermissionsConfirm2 = async () => {
  grantLoading.value = true
  const keys = treeRef2.value!.getCheckedKeys()
  grantUserHotelPermissionsApi(tableObject.currentRow?.id, sessionStore.getHotelId, keys)
    .then((res) => {
      if (res) {
        ElNotification({
          title: '操作成功',
          type: 'success'
        })
      }
    })
    .finally(() => {
      grantLoading.value = false
    })
}

const onTabsChange = async (e) => {
  if (tableObject.currentRow) {
    const hotel = grantHotels[e]
    const res = await getUserHotelPermissions(tableObject.currentRow.id, hotel.id)
    if (res) {
      nextTick(() => {
        treeRef.value!.setCheckedKeys(res.granted, false)
      })
    }
  }
}

const onRowClick = (row: User) => {
  tableObject.currentRow = row
}

const cellClassName = ({ row }) => {
  if (row.status === 'Locked') {
    return '!bg-red-500/50'
  }
}

const delData = async (row: User) => {
  tableObject.currentRow = row
  const { delList } = methods
  delLoading.value = true
  await delList([tableObject.currentRow?.id as string], false).finally(() => {
    delLoading.value = false
  })
}

const instance = reactive({
  xfull_name: '',
  login_name: ''
})
</script>

<template>
  <Search :model="instance" @search="setSearchParams" @reset="setSearchParams">
    <SearchItem label="姓名" prop="xfull_name">
      <ElInput v-model="instance.xfull_name" maxlength="50" clearable />
    </SearchItem>
    <SearchItem label="登录名" prop="login_name">
      <ElInput v-model="instance.login_name" maxlength="50" clearable />
    </SearchItem>
  </Search>

  <div class="mt-10px bg-white p-20px">
    <div class="mb-10px flex flex-row justify-between">
      <div>列表</div>
      <div class="flex flex-row items-center">
        <ElButton :icon="Plus" type="primary" @click="AddAction">新建</ElButton>
        <ElButton
          v-if="view_role === 'admin'"
          :icon="CirclePlus"
          type="primary"
          @click="grantAction"
          :disabled="!tableObject.currentRow"
        >
          授权
        </ElButton>
        <ElButton
          v-if="view_role === 'hotel'"
          v-hasPermi="'user:permission'"
          :icon="CirclePlus"
          type="primary"
          @click="grantAction2"
          :disabled="!tableObject.currentRow"
        >
          授权
        </ElButton>

        <ElButton
          v-hasPermi="'user:unlock'"
          :icon="Unlock"
          type="primary"
          @click="unlockAction"
          :disabled="!tableObject.currentRow"
        >
          解锁
        </ElButton>
        <ElButton
          v-hasPermi="'user:reset-password'"
          :icon="Lock"
          type="primary"
          @click="resetPasswordAction"
          :disabled="!tableObject.currentRow"
        >
          重置密码
        </ElButton>
        <Icon icon="ep:refresh-right" class="mr-8px ml-8px cursor-pointer" />
      </div>
    </div>

    <Table
      v-model:pageSize="tableObject.pageSize"
      v-model:currentPage="tableObject.currentPage"
      :columns="tableColumns"
      :data="tableObject.tableList"
      :loading="tableObject.loading"
      :pagination="{
        total: tableObject.total
      }"
      :selection="false"
      :cell-class-name="cellClassName"
      @register="register"
      @row-click="onRowClick"
    >
      <template #action="{ row }">
        <ElButton type="primary" link size="small" @click="EditAction(row)"> 编辑 </ElButton>
        <ElButton
          v-if="view_role === 'admin'"
          type="danger"
          link
          size="small"
          @click="delData(row)"
        >
          删除
        </ElButton>
        <ElButton
          v-if="view_role === 'hotel'"
          type="danger"
          link
          size="small"
          @click="revokeHotelAction2(row)"
        >
          移出
        </ElButton>
      </template>
    </Table>

    <ElDialog
      v-model="resetPasswordDialogVisible"
      :title="`重置密码 - 用户: ${tableObject.currentRow?.login_name}`"
      width="500px"
      draggable
      :close-on-click-modal="false"
      :close-on-press-escape="false"
    >
      <ElForm
        ref="resetPasswordFormRef"
        :model="resetPasswordInstance"
        label-width="100"
        :rules="resetPasswordRules"
      >
        <ElFormItem label="新密码" prop="password">
          <ElInput
            v-model="resetPasswordInstance.password"
            placeholder="新密码"
            type="password"
            show-password
            maxlength="50"
          />
        </ElFormItem>
        <ElFormItem label="验证密码" prop="grant_password">
          <ElInput
            v-model="resetPasswordInstance.grant_password"
            placeholder="您的密码"
            type="password"
            show-password
            maxlength="50"
          />
        </ElFormItem>
      </ElForm>

      <template #footer>
        <span class="dialog-footer">
          <el-button @click="resetPasswordDialogVisible = false">取消</el-button>
          <el-button type="primary" @click="onResetPasswordConfirm" :loading="resetPasswordLoading"
            >确认</el-button
          >
        </span>
      </template>
    </ElDialog>

    <ElDialog
      v-model="grantDialogVisible"
      :title="`授权 - 用户: ${tableObject.currentRow?.login_name}`"
      width="600px"
      :close-on-click-modal="false"
      :close-on-press-escape="false"
    >
      <ElForm ref="grantFormRef" :model="grantInstance" label-width="100">
        <ElFormItem label="主体列表">
          <ElSelect v-model="grantInstance.hotel_id" clearable filterable>
            <ElOption
              v-for="hotel of hotels"
              :key="hotel.id"
              :value="hotel.id!"
              :label="hotel.name!"
            />
          </ElSelect>

          <ElButton
            type="danger"
            @click="grantHotelAction"
            :disabled="!grantInstance.hotel_id"
            class="ml-10px"
          >
            授权
          </ElButton>
        </ElFormItem>

        <div class="flex flex-row">
          <ElTabs
            v-model="currentTab"
            tab-position="left"
            class="h-500px"
            @tab-change="onTabsChange"
          >
            <ElTabPane
              v-for="h of grantHotels"
              :key="h.id"
              :label="h.name!"
              class="max-h-500px overflow-y-auto"
            />
          </ElTabs>

          <div class="h-500px overflow-y-auto flex-grow">
            <div class="p-10px flex flex-row items-center justify-between">
              <ElCheckbox type="primary" @change="selectAllAction">全选/全不选</ElCheckbox>
              <ElCheckbox type="primary" @change="expandAction" checked>展开/折叠</ElCheckbox>
            </div>

            <ElTree
              ref="treeRef"
              :data="permissionTrees"
              show-checkbox
              :default-expand-all="true"
              node-key="id"
              highlight-current
              check-strictly
              :props="{ label: 'title' }"
            />
          </div>
        </div>
      </ElForm>

      <template #footer>
        <span class="dialog-footer">
          <ElButton
            type="danger"
            class="ml-10px"
            v-if="grantHotels.length > 0"
            @click="revokeHotelAction"
            >移出主体</ElButton
          >
          <el-button @click="grantDialogVisible = false">关闭</el-button>
          <el-button type="primary" @click="onGrantPermissionsConfirm" :loading="grantLoading">
            保存
          </el-button>
        </span>
      </template>
    </ElDialog>

    <ElDialog
      v-model="grantDialogVisible2"
      :title="`授权 - 用户: ${tableObject.currentRow?.login_name}`"
      width="600px"
      :close-on-click-modal="false"
      :close-on-press-escape="false"
    >
      <div class="h-500px overflow-y-auto flex-grow">
        <div class="p-10px flex flex-row items-center justify-between">
          <ElCheckbox type="primary" @change="selectAllAction2">全选/全不选</ElCheckbox>
          <ElCheckbox type="primary" @change="expandAction2" checked>展开/折叠</ElCheckbox>
        </div>

        <ElTree
          ref="treeRef2"
          :data="permissionTrees"
          show-checkbox
          :default-expand-all="true"
          node-key="id"
          highlight-current
          check-strictly
          :props="{ label: 'title' }"
        />
      </div>

      <template #footer>
        <span class="dialog-footer">
          <el-button @click="grantDialogVisible2 = false">关闭</el-button>
          <el-button type="primary" @click="onGrantPermissionsConfirm2" :loading="grantLoading">
            保存
          </el-button>
        </span>
      </template>
    </ElDialog>
  </div>
</template>
